#!/bin/sh
# -*- coding: utf-8 -*-
# Copyright (C) 2019 Checkmk GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

# Reason for this no-op: shellcheck disable=... before the first command disables the error for the
# entire script.
:

# Disable unused variable error (needed to keep track of version)
# shellcheck disable=SC2034
CMK_VERSION="2.5.0b1"

#
# Collects monitoring information of all IBM MQ Queue Managers.
#
# Environment configuration options:
#
# - Only monitor specific Queue Managers, e.g:
#     ONLY_QM="FOO BAR"
#
# - Explicitly skip certain Queue Managers, e.g:
#     SKIP_QM="FAULTY TOWER"
#
#
# Necessary IBM MQ rights, in case script does not run as mqm user:
#
#     set authrec objtype(QMGR) principal('cmkagent') authadd(DSP,INQ)
#     set authrec profile(**) objtype(QUEUE) principal('cmkagent') authadd(DSP)
#     set authrec profile(**) objtype(CHANNEL) principal('cmkagent') authadd(DSP)
#     set authrec profile(**) objtype(CLNTCONN) principal('cmkagent') authadd(DSP)
#

load_config() {
    # shellcheck source=/dev/null
    if test -s "$MK_CONFDIR/ibm_mq.cfg"; then
        . "$MK_CONFDIR"/ibm_mq.cfg
    fi
}

run_command() {
    input_command="$1"

    if test -n "$EXEC_USER" && test "$EXEC_USER" = "MQM"; then
        # Variable is defined and not empty
        concatenated_command="su mqm -c \"$input_command\""
        eval "$concatenated_command"
    else
        # Variable is not defined or empty
        eval "$input_command"
    fi
}

# Returns true (0) if list ($1) contains a value ($2).
contains() {
    for x in $1; do
        if test "$x" = "$2"; then
            return 0
        fi
    done
    return 1
}

# Returns true (0) if value ($1) is matched against configuration options
# SKIP_QM and ONLY_QM.
is_qm_monitored() {
    if test -n "$SKIP_QM"; then
        if contains "$SKIP_QM" "$1"; then
            echo "$1: Ignored because SKIP_QM: $SKIP_QM" >&2
            return 1
        fi
    fi
    if test -n "$ONLY_QM"; then
        if contains "$ONLY_QM" "$1"; then
            return 0
        else
            echo "$1: Ignored because ONLY_QM: $ONLY_QM" >&2
            return 1
        fi
    fi
    return 0
}

check_tool() {
    if command -v "$1" >/dev/null 2>&1; then
        echo "$1: OK"
    else
        echo "$1: Not found or not executable"
    fi
}

timestamp() {
    date +'%Y-%m-%dT%H:%M:%S'
}

load_config

echo "<<<ibm_mq_plugin:sep(58)>>>"
echo "version: $CMK_VERSION"
check_tool dspmq
check_tool runmqsc

dspmq -n | while read -r dspmqline; do
    QM=$(echo "$dspmqline" | sed 's,QMNAME(\([^)]*\).*,\1,')
    if is_qm_monitored "$QM"; then
        echo '<<<ibm_mq_channels:sep(10)>>>'
        section_channels=$(
            run_command "runmqsc -e \"$QM\"" <<EOF
display channel(*) xmitq
display chstatus(*) monitor
EOF
        )
        # For the channels, the order of computation does not matter, since the timestamp is
        # currently unused. For consistency, we do it in the same way as for the queues.
        echo "$dspmqline NOW($(timestamp))"
        echo "${section_channels}"
        echo '<<<ibm_mq_queues:sep(10)>>>'
        section_queues=$(
            run_command "runmqsc -e \"$QM\"" <<EOF
display qlocal(*) maxdepth maxmsgl crdate crtime altdate alttime monq
display qstatus(*) monitor ipprocs opprocs
EOF
        )
        # For the queues, it is important to compute the timestamp after the actual output data.
        # In the check plugin, we compute differences between timestamps from the output data and
        # this timestamp and these differences better not be negative ...
        echo "$dspmqline NOW($(timestamp))"
        echo "${section_queues}"
    fi
done

echo "<<<ibm_mq_managers:sep(10)>>>"
run_command "dspmq -o all -x -n"
